using Engine;
using Engine.Graphics;
using GameEntitySystem;
using TemplatesDatabase;

namespace Game {
    public class ComponentVrHandsModel : Component, IDrawable, IUpdateable {
        public SubsystemTerrain m_subsystemTerrain;

        public ComponentPlayer m_componentPlayer;

        public ComponentMiner m_componentMiner;

        public Model m_vrHandModel;

        public Vector3 m_itemOffset;

        public Vector3 m_itemRotation;

        public float m_pokeAnimationTime;

        public double m_nextHandLightTime;

        public float m_handLight;

        public int m_itemLight;

        public DrawBlockEnvironmentData m_drawBlockEnvironmentData = new();

        public PrimitivesRenderer3D m_primitivesRenderer = new();

        public static LitShader m_shader = new(2, false, false, true, false, false);

        public static int[] m_drawOrders = [1];

        public Vector3 ItemOffsetOrder { get; set; }

        public Vector3 ItemRotationOrder { get; set; }

        public int[] DrawOrders => m_drawOrders;

        public UpdateOrder UpdateOrder => UpdateOrder.FirstPersonModels;

        public virtual void Draw(Camera camera, int drawOrder) {
            if (!(m_componentPlayer.ComponentHealth.Health > 0f)
                || !camera.GameWidget.IsEntityFirstPersonTarget(Entity)
                || !m_componentPlayer.ComponentInput.IsControlledByVr) {
                return;
            }
            Vector3 eyePosition = m_componentPlayer.ComponentCreatureModel.EyePosition;
            int x = Terrain.ToCell(eyePosition.X);
            int num = Terrain.ToCell(eyePosition.Y);
            int z = Terrain.ToCell(eyePosition.Z);
            int activeBlockValue = m_componentMiner.ActiveBlockValue;
            if (Time.FrameStartTime >= m_nextHandLightTime) {
                float? num2 = LightingManager.CalculateSmoothLight(m_subsystemTerrain, eyePosition);
                if (num2.HasValue) {
                    m_nextHandLightTime = Time.FrameStartTime + 0.1;
                    m_handLight = num2.Value;
                }
            }
            Matrix identity = Matrix.Identity;
            if (m_pokeAnimationTime > 0f) {
                float num3 = MathF.Sin(MathF.Sqrt(m_pokeAnimationTime) * (float)Math.PI);
                if (activeBlockValue != 0) {
                    identity *= Matrix.CreateRotationX((0f - MathUtils.DegToRad(90f)) * num3);
                }
                else {
                    identity *= Matrix.CreateRotationX((0f - MathUtils.DegToRad(45f)) * num3);
                }
            }
            if (!VrManager.IsControllerPresent(VrController.Right)) {
                return;
            }
            Matrix matrix = VrManager.HmdMatrixInverted
                * Matrix.CreateWorld(camera.ViewPosition, camera.ViewDirection, camera.ViewUp)
                * camera.ViewMatrix;
            Matrix controllerMatrix = VrManager.GetControllerMatrix(VrController.Right);
            if (activeBlockValue == 0) {
                Display.DepthStencilState = DepthStencilState.Default;
                Display.RasterizerState = RasterizerState.CullCounterClockwiseScissor;
                m_shader.Texture = m_componentPlayer.ComponentCreatureModel.TextureOverride;
                m_shader.SamplerState = SamplerState.PointClamp;
                m_shader.MaterialColor = Vector4.One;
                m_shader.AmbientLightColor = new Vector3(m_handLight * LightingManager.LightAmbient);
                m_shader.DiffuseLightColor1 = new Vector3(m_handLight);
                m_shader.DiffuseLightColor2 = new Vector3(m_handLight);
                m_shader.LightDirection1 = -Vector3.TransformNormal(LightingManager.DirectionToLight1, camera.ViewMatrix);
                m_shader.LightDirection2 = -Vector3.TransformNormal(LightingManager.DirectionToLight2, camera.ViewMatrix);
                m_shader.Transforms.View = Matrix.Identity;
                m_shader.Transforms.Projection = camera.ProjectionMatrix;
                m_shader.Transforms.World[0] = Matrix.CreateScale(0.01f) * identity * controllerMatrix * matrix;
                foreach (ModelMesh mesh in m_vrHandModel.Meshes) {
                    foreach (ModelMeshPart meshPart in mesh.MeshParts) {
                        Display.DrawIndexed(
                            PrimitiveType.TriangleList,
                            m_shader,
                            meshPart.VertexBuffer,
                            meshPart.IndexBuffer,
                            meshPart.StartIndex,
                            meshPart.IndicesCount
                        );
                    }
                }
            }
            else {
                if (num >= 0
                    && num <= 255) {
                    TerrainChunk chunkAtCell = m_subsystemTerrain.Terrain.GetChunkAtCell(x, z);
                    if (chunkAtCell != null
                        && chunkAtCell.State >= TerrainChunkState.InvalidVertices1) {
                        m_itemLight = m_subsystemTerrain.Terrain.GetCellLightFast(x, num, z);
                    }
                }
                int num4 = Terrain.ExtractContents(activeBlockValue);
                Block block = BlocksManager.Blocks[num4];
                Vector3 vector = block.InHandRotation * ((float)Math.PI / 180f) + m_itemRotation;
                Matrix matrix2 = Matrix.CreateFromYawPitchRoll(vector.Y, vector.X, vector.Z)
                    * Matrix.CreateTranslation(block.InHandOffset)
                    * identity
                    * Matrix.CreateTranslation(m_itemOffset)
                    * controllerMatrix
                    * matrix;
                m_drawBlockEnvironmentData.DrawBlockMode = DrawBlockMode.FirstPerson;
                m_drawBlockEnvironmentData.SubsystemTerrain = m_subsystemTerrain;
                m_drawBlockEnvironmentData.InWorldMatrix = matrix2;
                m_drawBlockEnvironmentData.Humidity = m_subsystemTerrain.Terrain.GetHumidity(x, z);
                m_drawBlockEnvironmentData.Temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(x, z)
                    + SubsystemWeather.GetTemperatureAdjustmentAtHeight(num);
                m_drawBlockEnvironmentData.Light = m_itemLight;
                m_drawBlockEnvironmentData.EnvironmentTemperature = m_componentPlayer.ComponentVitalStats.EnvironmentTemperature;
                block.DrawBlock(m_primitivesRenderer, activeBlockValue, Color.White, block.InHandScale, ref matrix2, m_drawBlockEnvironmentData);
            }
            m_primitivesRenderer.Flush(camera.ProjectionMatrix);
        }

        public virtual void Update(float dt) {
            m_pokeAnimationTime = m_componentMiner.PokingPhase;
            m_itemOffset = Vector3.Lerp(m_itemOffset, ItemOffsetOrder, MathUtils.Saturate(10f * dt));
            m_itemRotation = Vector3.Lerp(m_itemRotation, ItemRotationOrder, MathUtils.Saturate(10f * dt));
            ItemOffsetOrder = Vector3.Zero;
            ItemRotationOrder = Vector3.Zero;
        }

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap) {
            m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
            m_componentPlayer = Entity.FindComponent<ComponentPlayer>(true);
            m_componentMiner = Entity.FindComponent<ComponentMiner>(true);
            m_vrHandModel = ContentManager.Get<Model>(valuesDictionary.GetValue<string>("VrHandModelName"));
        }
    }
}